package Spectrum

import (
	"fmt"
	DataSourceFile "lht-go-plugins/LhtDataSource/File"
	"lht-go-plugins/LhtPlugins/Algorithm/Demodulation"
	"lht-go-plugins/LhtPlugins/Algorithm/Demodulation/QpskGo"
	"lht-go-plugins/internal/core"
	"math"
	"net/http"
	"unsafe"
)

type SpectrumPlugin struct {
	*core.BasePlugin
}

func NewSpectrumPlugin() *SpectrumPlugin {
	return &SpectrumPlugin{
		BasePlugin: core.NewBasePlugin("spectrum", 1000),
	}
}

func (r *SpectrumPlugin) Init(cfg any) error {
	return nil
}
func (p *SpectrumPlugin) Name() string { return "Spectrum" }

const (
	PlotPointsW  = 1920
	PlotPointsH  = 1080
	MaxDB        = 0 // 根据你实际信号调整
	MinDB        = -120.0
	SampleFreq   = 20_000_000 //采样率
	CenterFreqHz = int64(255_000_000)
)

var (
	screenBuf = make([]float32, PlotPointsW)

	// 新增：QPSK 解调器实例（只初始化一次）
	qpskDemod *QpskGo.QPSKDemodulator
	demodInit = Demodulation.DemodulationInitParameter{
		Fs:   SampleFreq,
		Band: 5_000_000, // 根据你实际信号调整
		Rb:   2_048_000, // 2.048Mbps QPSK → 符号率 1.024M
	}
)

func (r *SpectrumPlugin) Start() error {
	hub := NewHub()
	go hub.Run()

	// 1. 创建广播器
	broadcaster := NewBroadcaster(32)
	go broadcaster.Run()

	// 2. 数据源 → 广播器
	go func() {
		fileSrc, err := DataSourceFile.NewFileDataSourceSimple("E:/1.92.dat")
		if err != nil {
			panic(err)
		}
		for raw := range fileSrc.GetChannel() {
			packet := make([]float32, len(raw))
			copy(packet, raw)
			broadcaster.Submit(packet)
		}
		broadcaster.Close()
	}()

	// 3. 频谱协程（订阅一份）
	go func() {
		ch := broadcaster.Subscribe()
		for rawFFT := range ch {
			GetScreenIntegerFFTData(
				PlotPointsH, PlotPointsW, MaxDB, MinDB,
				245_000_000-CenterFreqHz, 265_000_000-CenterFreqHz,
				SampleFreq, rawFFT, screenBuf,
			)

			select {
			case hub.broadcast <- SpectrumMsg{Type: "spectrum", Data: append([]float32(nil), screenBuf...)}:
			default:
			}
		}
	}()

	// 4. 解调协程（订阅另一份，完全独立）
	if false {
		go func() {
			ch := broadcaster.Subscribe()
			qpsk := QpskGo.NewQPSKDemodulator(Demodulation.DemodulationInitParameter{
				Fs: SampleFreq, Band: 5_000_000, Rb: 2_048_000,
			})
			baseTime := int64(0)
			const sliceSize = 8192

			for rawFFT := range ch {
				if len(rawFFT) < sliceSize*2 {
					continue
				}

				// 正确的零拷贝转换（Go 最新推荐写法）
				complexData := unsafe.Slice((*Demodulation.Complex)(unsafe.Pointer(&rawFFT[0])), len(rawFFT)/2)
				complexData = complexData[:sliceSize] // 取前 8192 个复样点

				result := qpsk.Demodulate(complexData, baseTime)
				if result != nil && result.Burst != nil && result.Burst.Length > 0 {
					cons := make([]float32, result.Burst.Length*2)
					for i, c := range result.Burst.SoftData {
						cons[i*2] = c.I
						cons[i*2+1] = c.Q
					}

					select {
					case hub.broadcast <- SpectrumMsg{
						Type:          "demod",
						Constellation: cons,
						Bits:          bitsToString(result.Burst.HardBits, 128),
						SNR:           estimateSNR(result.Burst.SoftData),
					}:
					default:
					}
				}
				baseTime += sliceSize
			}
		}()
	}

	// 5. Web 服务
	http.Handle("/", http.FileServer(http.Dir("E:/git/lht-go-plugins/LhtPlugins/Spectrum/static")))
	http.HandleFunc("/spec", UpgradeWebSocket(hub))
	fmt.Println("Spectrum + QPSK 实时解调已启动 → http://localhost:6661")
	go http.ListenAndServe(":6661", nil)

	return nil
}
func (r *SpectrumPlugin) handleData(data []byte) {
	// 模拟 redis 操作
	fmt.Printf("[redis] recv data: %s\n", string(data))
}

// 辅助函数
func bitsToString(bits []byte, max int) string {
	if len(bits) == 0 {
		return ""
	}
	n := len(bits)
	if n > max {
		n = max
	}
	s := make([]byte, n)
	for i := 0; i < n; i++ {
		s[i] = '0' + bits[i]&1
	}
	if len(bits) > max {
		return string(s) + "..."
	}
	return string(s)
}

func estimateSNR(symbols []Demodulation.Complex) float32 {
	if len(symbols) < 100 {
		return 0
	}
	var sumI, sumQ, sumPow float64
	for _, s := range symbols {
		sumI += float64(s.I)
		sumQ += float64(s.Q)
		sumPow += float64(s.I*s.I + s.Q*s.Q)
	}
	n := float64(len(symbols))
	meanI := sumI / n
	meanQ := sumQ / n
	signal := meanI*meanI + meanQ*meanQ
	noise := (sumPow/n - signal)
	if noise <= 1e-10 {
		return 99
	}
	return float32(10 * math.Log10(signal/noise))
}
